package HBFailureService;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.thrift.TException;
import org.ini4j.Ini;

import TopologyService.Topology;

/**
 * Class: HBHandler
 *
 */
public class HBHandler implements HBFailureService.Iface{
    
    // Member variables
	Map <String, Timer> mLive;
	private int processID;
	private int timeoutSec;
	
	private Topology topology;
	
	/**
	 * Constructor for HBHandler object
	 * 
	 * @param heartBeatIni ini section containing heartbeat information
	 */
	public HBHandler(Topology topology, int timeout) {
	    // Set the heatbeat ini section
	    //myIni = heartBeatIni;
	    
		this.topology = topology;
		
	    // Get process id
	    //Ini.Section section = heartBeatIni.get("Process");
	    processID =  topology.myID();
	    timeoutSec = timeout;
	    
	    mLive = new HashMap<String, Timer>();
	}
	
	@Override
	public synchronized void beat(HeartBeat b) throws TException {
	    // TODO Auto-generated method stub
	    int clientID = Integer.parseInt(b.getClientID());
	    System.out.println("Process " + this.processID + " received heartbeat from Client " + clientID);
	    Timer timer = null;
	    
	    if(clientID != topology.getNextID() && clientID != topology.getPrevID()){
	    	System.out.println("Process " +  processID +  " recieved unsolicited heartbeat from Client ID: " + clientID);
	        // nothing to do 
	        return;
	    }

	    timer = mLive.get(Integer.toString(clientID));
	    
	    if (timer != null) {
	        // Cancel the current timer
	        timer.cancel();
	        timer = null;
	    }
	        
        // Create a new timer object
        timer = new Timer();
        
        TimerExpired timerTask = new TimerExpired(clientID, topology);
        
        // Set the timer's schedule
        timer.schedule(timerTask, timeoutSec * 1000);
        
        // Get the current time
        Date date = new Date();
        SimpleDateFormat format = new SimpleDateFormat("dd.MM.yyyy hh:mm:ss");
        String current_time = format.format(date);
        
        System.out.println("Process " + processID + " Rescheduled " + clientID + "'s timeout for " + timeoutSec + " cur " + current_time);
        mLive.put(Integer.toString(clientID), timer);

	}
	
	/**
	 * Timer task executed when heart beat interval expires 
	 * 
	 */
	public class TimerExpired extends TimerTask{
	    
	    private int clientID;
	    private Topology topology;

	    /**
	     * 
	     * @param clientID ClientID this thread is monitoring
	     * @param m Map of ClientID to timer objects
	     * @param nodeID This node ID
	     */
	    TimerExpired(int clientID, Topology topology){
	        this.clientID = clientID;
	        this.topology = topology;
	    }
	    
	    /**
	     * Invoked upon timer expiration
	     */
	    public void run() {
	        // Get the current time
	        Date date = new Date();
	        SimpleDateFormat format = new SimpleDateFormat("dd.MM.yyyy hh:mm:ss");
	        String current_time = format.format(date);
	        
	        // are we still interested in this client?
	        if(clientID == topology.getNextID() || clientID == topology.getPrevID()){
		        System.out.println("Process " + topology.myID() + " Detected Failure! Client: " + clientID + " at: " + current_time);
		        topology.failureDetected(clientID);
	        }

	    }   
	}
}
